package router

import (
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
	"net/http"
	"strconv"
	"strings"
	"tieba_deseign/common"
	"tieba_deseign/db"
	redis "tieba_deseign/middleweare/cache"
	"tieba_deseign/models"
	"time"
)

func Routerall(router *gin.Engine) {

	r_post := router.Group("/post")
	{
		//设置中间件保证只有登录了才能进行后面的接口
		r_post.Use(AuthMiddleware())
		//获取所有帖子
		r_post.GET("/getallpost", GetAllPost)
		//创建帖子
		r_post.POST("/createpost", CreatePost)
		//根据id删除帖子
		r_post.DELETE("/deletepost", DeletePost)
		//根据id查询帖子
		r_post.GET("/getpostid", QueryPostById)
		//根据id更新帖子
		r_post.PUT("/updatepost", UpdatePostById)
	}
	r_login := router.Group("/log")
	{
		//用户注册
		r_login.POST("/register", UserRegister)
		//用户登录
		r_login.POST("/login", UserLogin)
	}
}

// 获取所有属于登录用户的帖子
func GetAllPost(c *gin.Context) {
	//根据获取用户数据
	admin_any, exists := c.Get("admin")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未找到用户信息"})
		return
	}
	admin := admin_any.(models.Admin)
	//构建承载体
	var posts_cache []models.Post
	//先从缓存中获取数据
	var error error
	posts_cache, error = redis.Getallpostbyadmin(redis.Rdb, c, admin)
	if error != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": error.Error()})
		return
	}
	//如果从缓存中未命中 则从数据库中获取数据
	if len(posts_cache) == 0 {
		posts_db, dberror := db.GetAllPosts(db.Db, admin)
		if dberror != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": dberror.Error()})
		}
		c.JSON(http.StatusOK, gin.H{"从db查询到的所有帖子为": posts_db})
		//将数据写入缓存当中 设置过期时间为1小时
		if err := redis.Createallpostcache(redis.Rdb, c, admin, posts_db, 1*time.Hour); err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
		}
		return
	}
	c.JSON(http.StatusOK, gin.H{"从redis查询到的所有帖子为": posts_cache})
}

// 创建帖子
func CreatePost(c *gin.Context) {
	//通过上下文获取用户的数据
	admin_any, _ := c.Get("admin")
	admin_struct := admin_any.(models.Admin)
	var post models.Post
	if err := c.ShouldBind(&post); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	////创建数据库的数据
	createdPost, error := db.CreatePost(db.Db, &post, &admin_struct)
	if error != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": error.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"被创建的帖子为": createdPost})
	//为缓存添加数据
	err := redis.Createpostcache(redis.Rdb, c, admin_struct, post, 1*time.Hour)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
		return
	}
}

// 根据id删除帖子
func DeletePost(c *gin.Context) {
	//根据上下文获取数据
	admin_any, _ := c.Get("admin")
	admin_struct := admin_any.(models.Admin)
	delete_id_str := c.Query("id")
	idUint64, error := strconv.ParseUint(delete_id_str, 10, 64)
	if error != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": error.Error()})
		return
	}
	//删除redis中的数据
	if err := redis.Deletepostcache(redis.Rdb, c, admin_struct, idUint64); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	//删除db中的数据
	error = db.DeletePost(db.Db, idUint64, admin_struct)
	if error != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": error.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"msg": "该数据已经被删除"})

}

// 用户根据id查询帖子
func QueryPostById(c *gin.Context) {
	query_id_str := c.Query("id")
	query_id_int, error := strconv.Atoi(query_id_str)
	//根据上下文获取数据
	admin_any, _ := c.Get("admin")
	admin_struct := admin_any.(models.Admin)
	if error != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": error.Error()})
		return
	}
	//从缓存中获取数据
	cachepost, err := redis.Getpostbyadmin(redis.Rdb, c, admin_struct, query_id_int)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	//从数据库中获取数据
	if cachepost == nil {
		dbpost, errordb := db.GetPostById(db.Db, query_id_int, admin_struct)
		if errordb != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": errordb.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"从数据库中获取的数据为": dbpost})
		//将数据写入缓存当中
		//将指针类型转换成正常类型
		cachepost := *dbpost
		err := redis.Createpostcache(redis.Rdb, c, admin_struct, cachepost, 1*time.Hour)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

	}
	c.JSON(http.StatusOK, gin.H{"从缓存中获取的数据为": cachepost})
}

// 根据id更新帖子
func UpdatePostById(c *gin.Context) {
	var post models.Post
	//根据上下文获取用户数据
	admin_any, _ := c.Get("admin")
	admin_struct := admin_any.(models.Admin)
	if err := c.ShouldBind(&post); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	//创建缓存
	err := redis.Createpostcache(redis.Rdb, c, admin_struct, post, 1*time.Hour)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	//为数据库创建数据
	UpdatePost, error := db.UpdatePost(db.Db, &post, post.ID, admin_struct)
	if error != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": error.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"更新的标题为": UpdatePost.Title,
		"更新的内容为": UpdatePost.Body})

}

// 用户登录的路由
func UserLogin(c *gin.Context) {
	var loginrequest models.LoginRequest
	if err := c.ShouldBind(&loginrequest); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	//根据用户名获取admin
	admin, error := db.GetAdminPassWord(db.Db, loginrequest.Username)
	if error != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": error.Error(),
			"msg":   "该用户不存在,请注册一个",
		})
		return
	}
	//需要使用bcrypt包比较
	if err := bcrypt.CompareHashAndPassword([]byte(admin.Password), []byte(loginrequest.Password)); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
			"msg":   "输入的密码错误,可以重试",
		})
		return
	}
	admin_json, err := json.Marshal(admin)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
		return
	}
	//生成jwt鉴权 jwt.NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption)
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"admin":    string(admin_json),
		"userid":   admin.ID,
		"username": admin.Username,
		"exp":      time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间为 24 小时
	})

	// 签名 Token
	tokenString, err := token.SignedString(common.Jwtkey)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "无法生成 Token"})
		return
	}
	//通过前端jwt_token处理存储在前端中
	c.JSON(http.StatusOK, gin.H{
		"msg":     "你已经登录成功",
		"你的登录令牌为": tokenString})
}

// 用户注册的路由
func UserRegister(c *gin.Context) {
	var Login_user models.LoginRequest
	if err := c.ShouldBind(&Login_user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	//确保密码符合格式
	if len(Login_user.Username) == 0 || len(Login_user.Password) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "输入的用户名或密码不符合格式",
		})
		return
	}
	if len(Login_user.Password) <= 5 {
		c.JSON(http.StatusBadRequest, gin.H{
			"msg": "输入的密码过短,请重新输入",
		})
		return
	}
	//保证用户不重复
	exist, error := db.FindUserByUserName(db.Db, Login_user.Username)
	if error != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": error.Error()})
		return
	}
	if exist {
		c.JSON(http.StatusBadRequest, gin.H{"msg": "该用户已经存在"})
		return
	} else {
		// 注册时加密密码
		hashPassword, _ := bcrypt.GenerateFromPassword([]byte(Login_user.Password), bcrypt.DefaultCost)
		admim := models.Admin{Username: Login_user.Username, Password: string(hashPassword)}
		if _, error := db.CreateAdmin(db.Db, &admim); error != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": error.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"msg":       "注册成功",
			"user_name": Login_user.Username,
			"已为你的密码加密":  string(hashPassword),
		})
	}

}

//authmiddleware中间件,用于验证用户登录

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		//从header获取token
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"msg": "输入数据为空",
			})
			c.Abort()
			return
		}
		//提取token
		tokenstirng := strings.TrimPrefix(authHeader, "Bearer ")
		if tokenstirng == authHeader || tokenstirng == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"msg": "无效验证信息",
			})
			c.Abort()
			return
		}
		//解析和验证token
		token, err := jwt.Parse(tokenstirng, func(token *jwt.Token) (interface{}, error) {
			//确保是HMAC签名方式
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, jwt.ErrSignatureInvalid
			}

			return common.Jwtkey, nil
		})
		//检查 Token 是否有效
		if err != nil || !token.Valid {
			if errors.Is(err, jwt.ErrTokenExpired) {
				c.JSON(http.StatusUnauthorized, gin.H{"error": "Token 已过期"})
			} else {
				c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的 Token"})
			}
			c.Abort()
			return
		}
		//获取token中的payload数据 其中claims数据有jwt.NewWithClaims函数构造的数据
		if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
			//设置上下文 方便后面获取用户数据为用户添加post
			var admin models.Admin
			admin_string := claims["admin"].(string)
			if err := json.Unmarshal([]byte(admin_string), &admin); err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
				return
			}
			c.Set("admin", admin)
			c.Next()
		} else {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": err.Error(),
			})
			c.Abort()
		}

	}
}
